#include <Arduino.h>

// 定义全局数组用于存储接收到的数据
const int MAX_BUFFER_SIZE = 256;
uint8_t receivedDataUART1[MAX_BUFFER_SIZE];
uint8_t receivedDataUART2[MAX_BUFFER_SIZE];
int dataIndexUART1 = 0;
int dataIndexUART2 = 0;

// 定义UART1的引脚
const int rxPinUART1 = 18;
const int txPinUART1 = 19;

// 定义UART2的引脚
const int rxPinUART2 = 16;
const int txPinUART2 = 17;

// 定义指示灯引脚
const int ledPin = 2;

// 定义全局变量用于存储转换后的整数，初始化为0
int16_t convertedInt = 0;

// 计算CRC16校验值
unsigned int calculateCRC16(uint8_t *data, int length) {
    unsigned int crc = 0xFFFF;
    for (int i = 0; i < length; i++) {
        crc ^= (unsigned int)data[i];
        for (int j = 0; j < 8; j++) {
            if (crc & 0x0001) {
                crc >>= 1;
                crc ^= 0xA001;
            } else {
                crc >>= 1;
            }
        }
    }
    return crc;
}

// 任务句柄
TaskHandle_t xTaskUART1 = NULL;
TaskHandle_t xTaskUART2 = NULL;

// 任务函数
void vTaskUART1(void *pvParameters);
void vTaskUART2(void *pvParameters);

void setup() {
    // 初始化串口监视器，波特率为115200
    Serial.begin(9600);
    Serial.println("Starting ESP32 FreeRTOS UART example...");

    // 初始化UART1，波特率为9600，并指定引脚
    Serial1.begin(9600, SERIAL_8N1, rxPinUART1, txPinUART1);

    // 初始化UART2，波特率为2400，并指定引脚
    Serial2.begin(2400, SERIAL_8N1, rxPinUART2, txPinUART2);

    // 初始化指示灯引脚为输出模式
    pinMode(ledPin, OUTPUT);

    // 创建任务
    xTaskCreate(
        vTaskUART1,           // 任务函数
        "TaskUART1",          // 任务名称
        4096,                 // 任务堆栈大小
        NULL,                 // 传递给任务的参数
        1,                    // 任务优先级
        &xTaskUART1           // 任务句柄
    );

    xTaskCreate(
        vTaskUART2,           // 任务函数
        "TaskUART2",          // 任务名称
        4096,                 // 任务堆栈大小
        NULL,                 // 传递给任务的参数
        1,                    // 任务优先级
        &xTaskUART2           // 任务句柄
    );
}

void loop() {
    // 主循环可以留空，所有工作由任务处理
    vTaskDelay(portMAX_DELAY); // 主循环休眠
}

// UART1处理任务 - 改进版
void vTaskUART1(void *pvParameters) {
    int lineNumber = 1; // 行号变量
    const TickType_t timeout = pdMS_TO_TICKS(5); // 5ms超时
    TickType_t lastByteTime = xTaskGetTickCount(); // 记录最后一个字节接收时间
    
    for (;;) { // 无限循环
        // 持续读取UART1数据，直到没有新数据且间隔超过50ms
        if (Serial1.available()) {
            // 有新数据到达，重置计时器并读取数据
             lastByteTime = xTaskGetTickCount();
             dataIndexUART1 = 0;
            
             // 读取所有可用数据
             while (Serial1.available() && dataIndexUART1 < MAX_BUFFER_SIZE) {
                 receivedDataUART1[dataIndexUART1++] = Serial1.read();
                 lastByteTime = xTaskGetTickCount(); // 更新最后接收时间
             }
            
             // 等待数据间隔超过50ms，表示一帧数据接收完毕
             while (xTaskGetTickCount() - lastByteTime < timeout) {
                // 检查是否有新数据到达
                if (Serial1.available()) {
                    // 有新数据，继续读取
                    while (Serial1.available() && dataIndexUART1 < MAX_BUFFER_SIZE) {
                        receivedDataUART1[dataIndexUART1++] = Serial1.read();
                        lastByteTime = xTaskGetTickCount(); // 更新最后接收时间
                    }
                 }
                 vTaskDelay(pdMS_TO_TICKS(1)); // 短暂延时避免CPU占用过高
            }
            
            // 数据接收完毕，打印接收到的数据
            Serial.print(lineNumber++);
            Serial.print(": Received data from UART1 in hex: ");
            for (int i = 0; i < dataIndexUART1; i++) {
                if (receivedDataUART1[i] < 0x10) {
                    Serial.print("0");
                }
                Serial.print(receivedDataUART1[i], HEX);
                Serial.print(" ");
            }
            Serial.println();
            
            // 检查数据长度是否足够进行CRC校验 (至少需要2字节CRC)
            if (dataIndexUART1 >= 4) { // 至少需要4字节：地址+功能码+数据+CRC
                // 提取接收到的CRC校验值 (低字节在前，高字节在后)
                uint16_t receivedCRC = (receivedDataUART1[dataIndexUART1-2]) | 
                                      (receivedDataUART1[dataIndexUART1-1] << 8);
                
                // 计算数据部分的CRC校验值 (不包含CRC本身)
                unsigned int calculatedCRC = calculateCRC16(receivedDataUART1, dataIndexUART1 - 2);
                
                // 验证CRC校验
                if (receivedCRC == calculatedCRC) {
                    Serial.print(lineNumber++);
                    Serial.println(": CRC verification passed");
                    
                    // 检查前两个字节是否为0x01和0x03
                    if (receivedDataUART1[0] == 0x01 && receivedDataUART1[1] == 0x03) {
                        // 生成Modbus RTU帧
                        uint8_t modbusFrame[9];
                        modbusFrame[0] = 0x01; // 从站地址
                        modbusFrame[1] = 0x03; // 功能码
                        modbusFrame[2] = 0x04; // 发送的字节个数
                        
                        // 将convertedInt强制转换为字节数组
                        uint8_t* bytearray = (uint8_t*)&convertedInt;
                        
                        // 存储转换后的 16 位整数
                        modbusFrame[3] = bytearray[1];
                        modbusFrame[4] = bytearray[0];
                        
                        // 存储转换后的 16 位整数
                        modbusFrame[5] = 0x00;
                        modbusFrame[6] = 0x00;
                        
                        // 计算CRC校验值
                        unsigned int crc = calculateCRC16(modbusFrame, 7);
                        modbusFrame[7] = crc & 0xFF; // CRC低字节
                        modbusFrame[8] = (crc >> 8) & 0xFF; // CRC高字节
                        
                        Serial.print(lineNumber++);
                        Serial.print(": Sending Modbus RTU frame via UART1: ");
                        for (int i = 0; i < 9; i++) {
                            Serial1.write(modbusFrame[i]);
                            if (modbusFrame[i] < 0x10) {
                                Serial.print("0");
                            }
                            Serial.print(modbusFrame[i], HEX);
                            Serial.print(" ");
                        }
                        Serial.println();
                    } else {
                        Serial.print(lineNumber++);
                        Serial.println(": Frame does not start with 0x01 0x03, ignoring");
                    }
                } else {
                    Serial.print(lineNumber++);
                    Serial.print(": CRC verification failed. Received: 0x");
                    Serial.print(receivedCRC, HEX);
                    Serial.print(", Calculated: 0x");
                    Serial.println(calculatedCRC, HEX);
                }
            } else {
                Serial.print(lineNumber++);
                Serial.println(": Data length is insufficient for CRC verification");
            }
        }
        
        // 没有数据时短暂延时，避免CPU占用过高
        vTaskDelay(pdMS_TO_TICKS(1));
    }
}

// UART2处理任务
void vTaskUART2(void *pvParameters) {
    int lineNumber = 1; // 行号变量
    for (;;) { // 无限循环
        // 处理UART2数据
        dataIndexUART2 = 0;
        if (Serial2.available()) {
            while (Serial2.available() && dataIndexUART2 < MAX_BUFFER_SIZE) {
                receivedDataUART2[dataIndexUART2++] = Serial2.read();
            }
            Serial.print(lineNumber++); // 打印行号
            Serial.print(": Received raw data from UART2 in hex: ");
            for (int i = 0; i < dataIndexUART2; i++) {
                if (receivedDataUART2[i] < 0x10) {
                    Serial.print("0");
                }
                Serial.print(receivedDataUART2[i], HEX);
                Serial.print(" ");
            }
            Serial.println();

            // 检查UART2接收数据的长度是否大于等于11且前两个字节是否为0x10和0x08
            if (dataIndexUART2 >= 11 && receivedDataUART2[0] == 0x10 && receivedDataUART2[1] == 0x08) {
                Serial.print(lineNumber++); // 打印行号
                Serial.print(": Received data from UART2 in hex: ");
                for (int i = 0; i < dataIndexUART2; i++) {
                    if (receivedDataUART2[i] < 0x10) {
                        Serial.print("0");
                    }
                    Serial.print(receivedDataUART2[i], HEX);
                    Serial.print(" ");
                }
                Serial.println();

                // 将第5, 6, 7, 8, 9位置的数据转换成字符串并拼接
                char combinedString[10];
                combinedString[0] = '\0';
                for (int i = 4; i < 9; i++) {
                    if (receivedDataUART2[i] == 0x0a) {
                        continue;
                    }
                    char temp[3];
                    snprintf(temp, sizeof(temp), "%X", receivedDataUART2[i]);
                    strcat(combinedString, temp);
                }
                Serial.print(lineNumber++); // 打印行号
                Serial.print(": Converted and combined string from 5th - 9th bytes: ");
                Serial.println(combinedString);

                // 将拼接后的字符串转换为十进制整数，使用int16_t类型接收
                int16_t intResult = atoi(combinedString);
                Serial.print(lineNumber++); // 打印行号
                Serial.print(": Converted string to decimal integer: ");
                Serial.println(intResult);

                // 将转换后的整数存入全局变量
                convertedInt = intResult;
                Serial.print(lineNumber++); // 打印行号
                Serial.print(": Global variable 'convertedInt' value: ");
                Serial.println(convertedInt);

                // 指示灯亮起
                digitalWrite(ledPin, HIGH);
                delay(400); // 这里可以继续使用delay，因为是在单独的任务中
                // 指示灯熄灭
                digitalWrite(ledPin, LOW);
            }
        }

        vTaskDelay(pdMS_TO_TICKS(1000)); // 短暂延时，释放CPU
    }
}